package org.nf.web.servlet.exception;

import cn.hutool.core.util.ReflectUtil;
import org.nf.web.servlet.BaseView;
import org.nf.web.servlet.FrameworkContext;
import org.nf.web.servlet.HandlerExceptionResolver;
import org.nf.web.servlet.annotation.ExceptionAdvice;
import org.nf.web.servlet.annotation.ExceptionHandler;
import org.nf.web.servlet.view.DefaultView;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * @author wangl
 * @date 2022/6/9
 * 全局异常处理器
 */
public class AnnotationHandlerExceptionResolver implements HandlerExceptionResolver {

    private final List<Method> handleExMethods = new ArrayList<>();

    /**
     * 初始化HandlerExceptionResolver
     */
    public AnnotationHandlerExceptionResolver() {
        Set<Class<?>> classes = FrameworkContext.getInstance().getClasses();
        parseHandleExMethods(classes);
        sortHandleExMethods();
    }

    /**
     * 扫描带有@ExceptionHandler注解的方法
     */
    private void parseHandleExMethods(Set<Class<?>> classes) {
        classes.forEach(clazz -> {
            if(clazz.isAnnotationPresent(ExceptionAdvice.class)) {
                for (Method method : clazz.getMethods()) {
                    if (method.isAnnotationPresent(ExceptionHandler.class)) {
                        handleExMethods.add(method);
                    }
                }
            }
        });
    }

    /**
     * 将异常处理方法按照从小到大的级别排序
     */
    @SuppressWarnings("all")
    private void sortHandleExMethods() {
        handleExMethods.sort((m1, m2) ->
                m1.getAnnotation(ExceptionHandler.class).value()
                        .isAssignableFrom(m2.getAnnotation(ExceptionHandler.class).value()) ? 1 : -1);
    }

    /**
     * 根据目标方法抛出的异常调用全局异常处理方法
     */
    @Override
    public BaseView resolveException(Throwable t) {
        BaseView view = null;
        for (Method method : handleExMethods) {
            //获取注解的value属性指定的异常Class对象
            Class<?> exceptionClass = method.getAnnotation(ExceptionHandler.class).value();
            //匹配全局异常对象
            if (exceptionClass.isAssignableFrom(t.getClass())) {
                //回调全局异常处理方法
                Object result = invokeHandlerMethod(method, t);
                //将返回的结果转换为视图对象
                view = resolveView(result);
                break;
            }
        }
        return view;
    }

    /**
     * 调用异常处理方法
     */
    private Object invokeHandlerMethod(Method method, Throwable e) {
        Object instance = ReflectUtil.newInstance(method.getDeclaringClass());
        return ReflectUtil.invoke(instance, method, e);
    }

    /**
     * 将返回结果转换为视图对象
     */
    private BaseView resolveView(Object result) {
        if (result != null) {
            //如果返回的result是View的实例则强转返回，否则将result包装为默认视图处理
            return result instanceof BaseView view ? view : new DefaultView(result);
        }
        return null;
    }
}
